﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using OverStore.Runtime.Storage;
using OverStore.Configuration.ObjectRepository.CommandSet;

namespace OverStore.Configuration.Builder.Fluent
{
    /// <summary>
    /// Exposes set of static methods for build command set configuration.
    /// </summary>
    public static class CommandSetBuilder<TNextStep>
    {
        /// <summary>
        /// 
        /// </summary>
        public class Parameters
        {
            private readonly Func<CommandSetConfiguration, TNextStep> _Completed;

            /// <summary>
            /// Initializes a new instance of the <see cref="CommandSetBuilder&lt;TNextStep&gt;.Parameters"/> class.
            /// </summary>
            /// <param name="completed">The completed.</param>
            public Parameters(Func<CommandSetConfiguration, TNextStep> completed)
            {
                _Completed = completed;
                Config = new CommandSetConfiguration();
            }

            /// <summary>
            /// Gets or sets the config.
            /// </summary>
            /// <value>The config.</value>
            public CommandSetConfiguration Config { get; set; }

            /// <summary>
            /// Completes this instance.
            /// </summary>
            /// <returns></returns>
            public TNextStep Complete()
            {
                return _Completed(Config);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public class SelectCommandStep
        {
            private readonly Parameters _P;

            /// <summary>
            /// Initializes a new instance of the <see cref="CommandSetBuilder&lt;TNextStep&gt;.SelectCommandStep"/> class.
            /// </summary>
            /// <param name="p">The p.</param>
            public SelectCommandStep(Parameters p)
            {
                if (Object.ReferenceEquals(p, null))
                    throw new ArgumentNullException("p");
                _P = p;
            }

            /// <summary>
            /// Withes the update command.
            /// </summary>
            public InsertCommandStep WithSelectCommand(IComponentConfiguration<ICommand> selectCommand)
            {
                if (Object.ReferenceEquals(selectCommand, null))
                    throw new ArgumentNullException("selectCommand");
                _P.Config.SelectCommand = selectCommand;
                return new InsertCommandStep(_P);
            }

            /// <summary>
            /// Configures delete command.
            /// </summary>
            public CommandBuilder<InsertCommandStep>.CommandTypeAndTextStep SelectCommand()
            {
                return new CommandBuilder<InsertCommandStep>.ResultGettingTypeStep(
                    new CommandBuilder<InsertCommandStep>.Parameters(c => WithSelectCommand(c)))
                .ExecuteAsReader();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public class InsertCommandStep
        {
            private readonly Parameters _P;

            /// <summary>
            /// Initializes a new instance of the <see cref="CommandSetBuilder&lt;TNextStep&gt;.InsertCommandStep"/> class.
            /// </summary>
            /// <param name="p">The p.</param>
            public InsertCommandStep(Parameters p)
            {
                if (Object.ReferenceEquals(p, null))
                    throw new ArgumentNullException("p");
                _P = p;
            }

            /// <summary>
            /// Withes the insert command.
            /// </summary>
            public UpdateCommandStep WithInsertCommand(IComponentConfiguration<ICommand> insertCommand)
            {
                if (Object.ReferenceEquals(insertCommand, null))
                    throw new ArgumentNullException("insertCommand");
                _P.Config.InsertCommand = insertCommand;
                return new UpdateCommandStep(_P);
            }

            /// <summary>
            /// Configures delete command.
            /// </summary>
            public CommandBuilder<UpdateCommandStep>.CommandTypeAndTextStep InsertCommand()
            {
                return new CommandBuilder<UpdateCommandStep>.ResultGettingTypeStep(
                    new CommandBuilder<UpdateCommandStep>.Parameters(c => WithInsertCommand(c)))
                .ExecuteAsCommand();
            }

            /// <summary>
            /// Omit configuration of insert, update and delete commands.
            /// </summary>
            public EndStep AsReadOnly()
            {
                return new EndStep(_P);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public class UpdateCommandStep
        {
            private readonly Parameters _P;

            /// <summary>
            /// Initializes a new instance of the <see cref="CommandSetBuilder&lt;TNextStep&gt;.UpdateCommandStep"/> class.
            /// </summary>
            /// <param name="p">The p.</param>
            public UpdateCommandStep(Parameters p)
            {
                if (Object.ReferenceEquals(p, null))
                    throw new ArgumentNullException("p");
                _P = p;
            }

            /// <summary>
            /// Withes the update command.
            /// </summary>
            public DeleteCommandStep WithUpdateCommand(IComponentConfiguration<ICommand> updateCommand)
            {
                if (Object.ReferenceEquals(updateCommand, null))
                    throw new ArgumentNullException("updateCommand");
                _P.Config.UpdateCommand = updateCommand;
                return new DeleteCommandStep(_P);
            }

            /// <summary>
            /// Configures delete command.
            /// </summary>
            public CommandBuilder<DeleteCommandStep>.CommandTypeAndTextStep UpdateCommand()
            {
                return new CommandBuilder<DeleteCommandStep>.ResultGettingTypeStep(
                    new CommandBuilder<DeleteCommandStep>.Parameters(c => WithUpdateCommand(c)))
                .ExecuteAsCommand();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public class DeleteCommandStep
        {
            private readonly Parameters _P;

            /// <summary>
            /// Initializes a new instance of the <see cref="CommandSetBuilder&lt;TNextStep&gt;.DeleteCommandStep"/> class.
            /// </summary>
            /// <param name="p">The p.</param>
            public DeleteCommandStep(Parameters p)
            {
                if (Object.ReferenceEquals(p, null))
                    throw new ArgumentNullException("p");
                _P = p;
            }

            /// <summary>
            /// Configures command set with delete command.
            /// </summary>
            public EndStep WithDeleteCommand(IComponentConfiguration<ICommand> deleteCommand)
            {
                if (Object.ReferenceEquals(deleteCommand, null))
                    throw new ArgumentNullException("deleteCommand");

                _P.Config.DeleteCommand = deleteCommand;
                return new EndStep(_P);
            }

            /// <summary>
            /// Configures delete command.
            /// </summary>
            public CommandBuilder<EndStep>.CommandTypeAndTextStep DeleteCommand()
            {
                return new CommandBuilder<EndStep>.ResultGettingTypeStep(
                    new CommandBuilder<EndStep>.Parameters(c => WithDeleteCommand(c)))
                .ExecuteAsCommand();
            }

            /// <summary>
            /// Performs the delete as update.
            /// </summary>
            public EndStep PerformDeleteAsUpdate()
            {
                _P.Config.DeleteCommand = _P.Config.UpdateCommand;
                return new EndStep(_P);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public class EndStep
        {
            private readonly Parameters _P;

            /// <summary>
            /// Initializes a new instance of the <see cref="CommandSetBuilder&lt;TNextStep&gt;.EndStep"/> class.
            /// </summary>
            /// <param name="p">The p.</param>
            public EndStep(Parameters p)
            {
                if (Object.ReferenceEquals(p, null))
                    throw new ArgumentNullException("p");
                _P = p;
            }

            /// <summary>
            /// Ends the command set.
            /// </summary>
            public TNextStep EndCommandSet()
            {
                return _P.Complete();
            }
        }
    }
}
